package initConfig

import (
	"database/sql"
	"fmt"

	"github.com/google/uuid"
	"go.uber.org/zap"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var GormDb *gorm.DB // 全局数据库连接实例
var SqlDb *sql.DB   // 底层的 *sql.Db 实例

// InitDB 初始化 MySQL 数据库连接，并确保数据库存在
func InitDB(dbConfig DatabaseConfig) {
	var err error

	// 第一步：使用不带数据库名的 DSN 连接到 MySQL 服务器（连接到 mysql 系统库）
	dsnWithoutDB := fmt.Sprintf("%s:%s@tcp(%s:%d)/mysql?charset=utf8mb4&parseTime=True&loc=Local",
		dbConfig.User,
		dbConfig.Password,
		dbConfig.Host,
		dbConfig.Port,
	)

	tempDb, err := gorm.Open(mysql.Open(dsnWithoutDB), &gorm.Config{})
	if err != nil {
		zap.L().Fatal("无法连接到 MySQL 服务器", zap.Error(err))
	}

	sqlDB, err := tempDb.DB()
	if err != nil {
		zap.L().Fatal("无法获取底层 *sql.DB 实例（用于创建数据库）", zap.Error(err))
	}

	// 创建数据库（如果不存在）
	createDBSQL := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;", dbConfig.Name)
	_, err = sqlDB.Exec(createDBSQL)
	if err != nil {
		zap.L().Fatal("无法创建数据库", zap.String("database", dbConfig.Name), zap.Error(err))
	}

	zap.L().Info("数据库已确保存在", zap.String("database", dbConfig.Name))

	// 第二步：现在使用完整的 DSN 连接到目标数据库
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		dbConfig.User,
		dbConfig.Password,
		dbConfig.Host,
		dbConfig.Port,
		dbConfig.Name,
	)

	GormDb, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		zap.L().Fatal("无法连接到目标数据库", zap.String("database", dbConfig.Name), zap.Error(err))
	}

	SqlDb, err = GormDb.DB()
	if err != nil {
		zap.L().Fatal("无法获取底层的 *sql.DB 实例", zap.Error(err))
	}

	err = SqlDb.Ping()
	if err != nil {
		zap.L().Fatal("无法 ping 通目标数据库", zap.Error(err))
	}

	// 创建表
	createTables()

	zap.L().Info("数据库初始化成功！！！")
}

// createTables 手动执行 SQL 脚本创建表
func createTables() {
	// 定义 SQL 脚本
	createDepartmentsTable := `
	CREATE TABLE IF NOT EXISTS departments (
		id VARCHAR(36) PRIMARY KEY,
		name VARCHAR(10) UNIQUE
	);`

	createUsersTable := `
	CREATE TABLE IF NOT EXISTS users (
		id VARCHAR(36) PRIMARY KEY,
		account VARCHAR(20),
		username VARCHAR(10),
		gender VARCHAR(2),
		phone VARCHAR(11),
		password VARCHAR(100),
		add_time VARCHAR(20),
		is_manager TINYINT,
		department VARCHAR(10),
		FOREIGN KEY (department) REFERENCES departments(name)
	);`

	createVideosTable := `
	CREATE TABLE IF NOT EXISTS videos (
		id VARCHAR(36) PRIMARY KEY NOT NULL,
		video_url VARCHAR(255),
		cover_url VARCHAR(255),
		size VARCHAR(20),
		name VARCHAR(20),
		uploader VARCHAR(10),
		content VARCHAR(200),
		record_time VARCHAR(20),
		upload_time VARCHAR(20),
		file_path VARCHAR(255)
	);`

	//createVideoMetadataTable := `
	//CREATE TABLE IF NOT EXISTS video_metadata (
	//	id BIGINT AUTO_INCREMENT PRIMARY KEY,
	//	video_id VARCHAR(36) NOT NULL,
	//	width INT,
	//	height INT,
	//	fps FLOAT,
	//	duration INT,
	//	file_type VARCHAR(32),
	//	file_size BIGINT,
	//	create_time BIGINT,
	//	modify_time BIGINT,
	//	md5 CHAR(32)
	//);`

	// 执行 SQL 脚本
	execSQL(createDepartmentsTable)
	execSQL(createUsersTable)
	execSQL(createVideosTable)
	//execSQL(createVideoMetadataTable)

	// 插入 admin 管理员
	insertAdmin()
}

func insertAdmin() {
	// 检查是否已有 admin 用户
	var exists bool
	err := SqlDb.QueryRow("SELECT EXISTS(SELECT 1 FROM users WHERE account = 'admin')").Scan(&exists)
	if err != nil {
		zap.L().Fatal("无法检查 admin 用户是否存在", zap.Error(err))
	}

	if exists {
		// 删除已有 admin 用户
		_, err := SqlDb.Exec("DELETE FROM users WHERE account = 'admin'")
		if err != nil {
			zap.L().Fatal("删除已有 admin 用户失败", zap.Error(err))
		}
		zap.L().Info("已删除旧的 admin 用户")
	}

	// 生成 UUID
	id, err := uuid.NewRandom()
	if err != nil {
		zap.L().Fatal("无法添加 admin 用户", zap.Error(err))
	}

	// 加密密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)
	if err != nil {
		zap.L().Fatal("无法添加 admin 用户", zap.Error(err))
	}

	// 插入新 admin 用户
	insertAdmin := fmt.Sprintf(`
		INSERT INTO users (id, account, username, password, gender, is_manager)
		VALUES ('%s', 'admin', 'admin', '%s', '男', 1)
	`, id.String(), string(hashedPassword))

	execSQL(insertAdmin)

	zap.L().Info("管理员用户 admin 已成功添加")
}

// execSQL 执行 SQL 语句并处理错误
func execSQL(query string) {
	_, err := SqlDb.Exec(query)
	if err != nil {
		zap.L().Fatal("执行 SQL 失败", zap.String("query", query), zap.Error(err))
	}
}
